#!/usr/bin/env bash
# ============================================================================
# KWS NEW SYSTEM — TASERON KORUMA pre-commit GUVENLIK KILIDI (v2 sertlestirilmis)
# ----------------------------------------------------------------------------
# Amac: Antigravity / taseron / yetkisiz ajan commit'lerinin finans, RBAC,
#       guvenlik, veri-goc cekirdegine ya da yonetisim/kafes dosyalarina
#       dokunmasini ENGELLEMEK.
#
# Politika kaynagi (manifest): kws-yeni/.taseron-korumali-yollar.txt
#   "MD_OK: <glob>"  -> yol bloklanir AMA gercek *.md (tek-uzanti, kod-uzantisi
#                       gizlemeyen) dosyalar serbest
#   "HARD: <glob>"   -> KOSULSUZ blok (.md / cift-uzanti olsa bile)
#   "#" ile baslayan -> yorum
#
# SERTLESTIRMELER (red-team bulgularina karsi):
#   - diff-filter=ACMRDT : Delete (D) ve Typechange (T) de denetlenir.
#       Korumali dosyayi SILMEK veya symlink'e cevirmek de IHLAL'dir.
#   - lowercase eslestirme : Auth.js / AUTH.JS / Fatura.JS de yakalanir.
#   - CRLF temizleme : manifest CRLF kaydedilse de glob'lar bozulmaz
#       (aksi halde sessiz fail-OPEN olurdu).
#   - cift-uzanti farkindali .md carve-out : server.js.md gibi dosyalar
#       MD_OK serbestligi alamaz (ikinci kod-uzantisi varsa .md sayilmaz).
#   - manifest/hook SILME ozel kontrolu : kafesi sokmek icin silme reddedilir.
#   - fail-closed : manifest yoksa veya repo koku bulunamazsa REDDET.
#
# Kacis kapisi : CLAUDE_REVIEWED=1  -> hook bastan gecer (yalniz yonetici Claude)
#   UYARI: bu CLIENT hook'tur. "git commit --no-verify" hook'u HIC calistirmaz.
#          Taserona kural: --no-verify / -n KESINLIKLE YASAK. Gercek zorlama
#          server-side (pre-receive) + branch-protection + CI ile yapilmali.
# ============================================================================
set -eu

# --- 0) Yonetici kacis kapisi -------------------------------------------------
if [ "${CLAUDE_REVIEWED:-}" = "1" ]; then
  exit 0
fi

# --- 1) Repo koku + manifest yolu (fail-closed) ------------------------------
REPO_ROOT="$(git rev-parse --show-toplevel 2>/dev/null)" || {
  echo "TASERON-KILIT: git repo koku bulunamadi -> commit REDDEDILDI (fail-closed)." >&2
  exit 1
}
if [ -z "${REPO_ROOT:-}" ]; then
  echo "TASERON-KILIT: repo koku bos -> commit REDDEDILDI (fail-closed)." >&2
  exit 1
fi
MANIFEST="$REPO_ROOT/kws-yeni/.taseron-korumali-yollar.txt"

# --- 2) FAIL-CLOSED: manifest yoksa reddet -----------------------------------
if [ ! -f "$MANIFEST" ]; then
  echo "TASERON-KILIT: Manifest bulunamadi -> $MANIFEST" >&2
  echo "TASERON-KILIT: Guvenlik geregi commit REDDEDILDI (fail-closed)." >&2
  exit 1
fi

# --- 3) Staged dosyalar: A C M R + D(delete) + T(typechange) -----------------
# D ve T eklendi: korumali dosyayi SILMEK veya symlink'e cevirmek de denetlenir.
STAGED="$(git diff --cached --name-only --diff-filter=ACMRDT)"
if [ -z "$STAGED" ]; then
  exit 0
fi

# --- 4) lowercase yardimcisi (buyuk/kucuk harf bypass'i kapatir) -------------
lc() { printf '%s' "$1" | tr '[:upper:]' '[:lower:]'; }

# --- 5) Glob eslestirme yardimcisi (lowercase yollar uzerinde) ---------------
# Desteklenen kaliplar:
#   "dizin/*"   -> TUM alt-dizinler (derin) -> onek eslesmesi
#   "dizin/**"  -> ayni (acik derin-prefix)
#   "**/kuyruk" -> herhangi derinlikte basename/kuyruk
#   duz fnmatch -> dogrudan (ornek: kws-yeni/server.js, package.json)
yol_eslesir() {
  glob="$1"; yol="$2"

  # "dizin/**" -> onek eslesmesi (derin)
  case "$glob" in
    */\*\*)
      onek="${glob%/\*\*}"
      case "$yol" in
        "$onek"/*) return 0 ;;
      esac
      return 1
      ;;
  esac

  # "dizin/*" -> TUM alt-dizinleri kapsamali (derin) -> onek eslesmesi
  case "$glob" in
    */\*)
      onek="${glob%/\*}"
      case "$yol" in
        "$onek"/*) return 0 ;;
      esac
      return 1
      ;;
  esac

  # "**/kuyruk" -> herhangi derinlik (kokte de alt-dizinde de)
  case "$glob" in
    \*\*/*)
      kuyruk="${glob#\*\*/}"
      case "$yol" in
        $kuyruk) return 0 ;;        # kok seviyesi
        */$kuyruk) return 0 ;;      # alt-dizin
      esac
      # kuyruk dizin icermiyorsa basename uzerinden de dene
      case "$kuyruk" in
        */*) : ;;
        *) case "${yol##*/}" in $kuyruk) return 0 ;; esac ;;
      esac
      return 1
      ;;
  esac

  # "dizin/<tek-segment-kalip>"  (ornek: kws-yeni/*.js, kws-yeni/app.*)
  # DIKKAT: shell fnmatch'inde '*' '/' karakterini de gecer; bu yuzden
  # "kws-yeni/*.js" yanlislikla "kws-yeni/dashboard/x.js"i yakalardi.
  # Cozum: glob bir '/' iceriyorsa ve son segmentinde '/' YOKsa, yol ile
  # ayni DIZIN-ONEKINE sahip olmali VE kalan kisimda fazladan '/' OLMAMALI.
  case "$glob" in
    */*)
      gdizin="${glob%/*}"          # "kws-yeni"
      gson="${glob##*/}"           # "*.js"
      # yol ayni dizin onekinde mi?
      case "$yol" in
        "$gdizin"/*)
          kalan="${yol#"$gdizin"/}"   # "app.js" veya "dashboard/x.js"
          case "$kalan" in
            */*) return 1 ;;          # fazladan dizin -> tek-segment kalip eslemez
            *) case "$kalan" in $gson) return 0 ;; esac ;;
          esac
          ;;
      esac
      return 1
      ;;
  esac

  # Duz fnmatch (dizin icermeyen tam kalip, ornek: AGENTS.md, some.patch)
  case "$yol" in
    $glob) return 0 ;;
    */$glob) return 0 ;;   # kok-disi yollarda da basename eslesmesi
  esac
  return 1
}

# --- 6) GERCEK .md mi? (cift-uzanti / gomulu kod-uzantisi .md sayilmaz) -------
# server.js.md, auth.ts.md GIBI dosyalar MD_OK serbestligi ALMAZ.
gercek_md() {
  ad="$1"   # zaten lowercase
  case "$ad" in
    *.md) : ;;
    *) return 1 ;;
  esac
  # ".md" oncesi govdede ikinci bir kod-uzantisi varsa -> gizleme, .md DEGIL
  govde="${ad%.md}"
  case "$govde" in
    *.js|*.mjs|*.cjs|*.ts|*.tsx|*.jsx|*.py|*.go|*.sh|*.rb|*.php|*.json) return 1 ;;
  esac
  return 0
}

# --- 7) Manifest/hook SILME ozel kontrolu ------------------------------------
# Kafesi sokmek icin manifest veya hook'u silmeyi/yeniden-adlandirmayi reddet.
# (HARD globlari zaten yakalar; bu acik+net hata mesaji icin ek kalkan.)
DEL="$(git diff --cached --name-only --diff-filter=D)"
while IFS= read -r d; do
  [ -z "$d" ] && continue
  dl="$(lc "$d")"
  case "$dl" in
    *taseron-korumali-yollar*|*/git-hooks/*|*git-hooks/pre-commit*)
      echo "TASERON-KILIT: Kafes dosyasini SILME girisimi reddedildi -> $d" >&2
      exit 1
      ;;
  esac
done <<EOF
$DEL
EOF

# --- 8) Manifest'i tara, her staged dosyayi denetle --------------------------
IHLAL=0
IHLAL_LISTE=""

while IFS= read -r ham || [ -n "$ham" ]; do
  # CRLF temizle (manifest CRLF kaydedilirse sessiz fail-OPEN olmasin)
  ham="${ham%$'\r'}"

  case "$ham" in
    \#*|"") continue ;;
  esac

  kademe=""
  glob=""
  case "$ham" in
    MD_OK:*) kademe="MD_OK"; glob="${ham#MD_OK:}" ;;
    HARD:*)  kademe="HARD";  glob="${ham#HARD:}" ;;
    *) continue ;;
  esac
  # bas/son bosluk kirp + CR temizle
  glob="${glob%$'\r'}"
  glob="${glob#"${glob%%[![:space:]]*}"}"
  glob="${glob%"${glob##*[![:space:]]}"}"
  [ -z "$glob" ] && continue
  glob="$(lc "$glob")"

  while IFS= read -r dosya; do
    [ -z "$dosya" ] && continue
    dosya_lc="$(lc "$dosya")"
    if yol_eslesir "$glob" "$dosya_lc"; then
      if [ "$kademe" = "MD_OK" ] && gercek_md "$dosya_lc"; then
        continue   # MD_OK: gercek *.md serbest
      fi
      IHLAL=1
      IHLAL_LISTE="$IHLAL_LISTE  [$kademe] $dosya  (kalip: $glob)
"
    fi
  done <<EOF
$STAGED
EOF
done < "$MANIFEST"

# --- 9) Karar ----------------------------------------------------------------
if [ "$IHLAL" -eq 1 ]; then
  echo "=============================================================" >&2
  echo " TASERON-KILIT: KORUMALI YOLLARA COMMIT ENGELLENDI" >&2
  echo "-------------------------------------------------------------" >&2
  echo " Asagidaki staged dosyalar korumali (finans/RBAC/guvenlik/goc" >&2
  echo " veya yonetisim/kafes) cekirdegine ait. Taseron ajan bunlari" >&2
  echo " degistiremez/silemez." >&2
  echo "" >&2
  printf '%s' "$IHLAL_LISTE" >&2
  echo "-------------------------------------------------------------" >&2
  echo " Cozum: degisikligi staged'dan cikar:  git restore --staged <dosya>" >&2
  echo "        veya yetkili yonetici Claude incelemesinden gecir:" >&2
  echo "        CLAUDE_REVIEWED=1 git commit ...   (YALNIZ yonetici)" >&2
  echo "" >&2
  echo " UYARI: 'git commit --no-verify' bu kilidi HIC calistirmaz." >&2
  echo "        Taserona --no-verify / -n KESINLIKLE YASAKtir." >&2
  echo "=============================================================" >&2
  exit 1
fi

exit 0
